/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package compilador.analisadorSintatico;

import compilador.analisadorLexico.Token;
import compilador.analisadorSintatico.classe.CLASSE;
import compilador.analisadorSintatico.simboloGramatical.ArvoreSintatica;
import compilador.analisadorSintatico.simboloGramatical.ErroSintatico;
import compilador.analisadorSintatico.simboloGramatical.NaoTerminal;
import compilador.analisadorSintatico.simboloGramatical.SimboloGramatical;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Thiago
 */
public class AnalisadorSintatico {
    public static final boolean DEBUG = true;

    private TokenReader tokenReader;

    private ArvoreSintatica arvoreSintatica;
    
    private List<ErroSintatico> erros;
    
    public AnalisadorSintatico(TokenReader tokenReader) {
        this.tokenReader = tokenReader;
        
        arvoreSintatica = new ArvoreSintatica();
    }
    
    public AnalisadorSintatico(List<Token> tokens) {
        this.tokenReader = TokenReader.createInstance(tokens);
        this.erros = new ArrayList<ErroSintatico>();
        
        arvoreSintatica = new ArvoreSintatica();
    }

    public List<ErroSintatico> getErros() {
        return erros;
    }
    
    public void analisar(){
        Producao classe = new CLASSE();
        //Producao classe = new CMD(); 
        SimboloGramatical classeSG = null;
        
        try {
            classeSG = classe.derivar();
        } catch (Exception ex) {
            System.err.println(ex);
        }

        if(tokenReader.hasToken()){
            ErroSintatico erroSint =  new ErroSintatico();

            while(tokenReader.hasToken()){
                erroSint.add(tokenReader.consome());
            }
            
            erroSint.setDescricao("Símbolos a partir de '"+ erroSint.getTokens().get(0).getAtributo() +"' não pertencem a nenhuma classe.");
            
            if(classeSG != null){
                if(classeSG instanceof NaoTerminal)
                        ((NaoTerminal) classeSG).add(erroSint);
            }else
                classeSG = erroSint;
        }
        
        arvoreSintatica.setRaiz(classeSG);
        
        extractErrosSintaticos(arvoreSintatica.getRaiz());
    }

    public ArvoreSintatica getArvoreSintatica() {
        return arvoreSintatica;
    }
    
    //busca em profundidade por erros na gramática
    private void extractErrosSintaticos(SimboloGramatical sg){
        List<SimboloGramatical> filhos;
        
        if(sg instanceof NaoTerminal){
            NaoTerminal nt = (NaoTerminal) sg;
            
            filhos = nt.getFilhos();
            
            for(SimboloGramatical sgFilho: filhos){
                extractErrosSintaticos(sgFilho);
                
            }
            
        } else if(sg instanceof ErroSintatico){
            erros.add((ErroSintatico) sg);
        }
    }
    
}
